/**
 * Copyright (C) 2011 Denatics Development
 * 
 * Programmed by David Tiersch <dtiersch@denatics.com>
 * 
 * This file is part of B0mberman.
 * 
 * B0mberman is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * B0mberman is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with B0mberman. If not, see <http://www.gnu.org/licenses/>.
 */
package com.denatics.bomberman.gui;

import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;

import javax.swing.JFrame;

import com.denatics.bomberman.Config;
import com.denatics.bomberman.engine.GameAPI;
import com.denatics.bomberman.tools.Debugger;
import com.denatics.bomberman.tools.Tickable;

/**
 * The "Window" in which the whole game will be rendered.
 * 
 * @author David Tiersch <dtiersch@denatics.com>
 */
public final class Screen extends JFrame implements Tickable {

    /**
     * FPS: Needed to convert between seconds and milliseconds.
     */
    private static final int MILLISEC = 1000000000;

    /**
     * Size of the border (on both sides).
     */
    private static final int BORDERSIZE = 2;

    /**
     * Default UID.
     */
    private static final long serialVersionUID = 1L;

    /**
     * Sets the Buffer-Strategy to triple-buffer.
     */
    private static final int BUFFER = 3;

    /**
     * Reference to the running game.
     */
    private GameAPI game;

    /**
     * ImageBuffer.
     */
    private BufferedImage img;

    /**
     * This object renders the field itself.
     */
    private GameField field;

    /**
     * Array with the image being rendered.
     */
    private int[] pixels;

    /**
     * FPS: Counts the Frames.
     */
    private int fpsc = 0;

    /**
     * FPS: Counts the time to know when a second is over.
     */
    private double fpstime = 0.0;

    /**
     * FPS: Time of the last tick.
     */
    private long lastTime = 0;

    /**
     * Creates the Window.
     */
    public Screen() {
        super(Config.NAME);
        this.setUndecorated(true);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setSize((Config.FIELD_DIM[0] + BORDERSIZE) * Config.ENTITYSIZE
                * Config.SCALE, (Config.FIELD_DIM[1] + BORDERSIZE)
                * Config.ENTITYSIZE * Config.SCALE);
        this.setLocation(Config.WIN_OFFSET[0], Config.WIN_OFFSET[1]);

        this.img =
                new BufferedImage(getWidth(), getHeight(),
                        BufferedImage.TYPE_INT_RGB);
        this.pixels =
                ((DataBufferInt) img.getRaster().getDataBuffer()).getData();

        this.field = new GameField();

        Debugger.printInfo("Window initialized");
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.denatics.bomberman.Tickable#tick()
     */
    @Override
    public void tick() {
        if (this.hasFocus()) {
            // FPS-Counter
            if (true) {
                fpsc++;
                long now = System.nanoTime();
                long passedTime = now - lastTime;
                lastTime = now;
                fpstime += passedTime / (double) MILLISEC;
                if (fpstime >= 1) {
                    Debugger.printInfo(fpsc + " FPS");
                    fpsc = 0;
                    fpstime = 0.0;
                }
            }

            ((Tickable) this.game).tick();

            // A little render-performance
            BufferStrategy strategy = getBufferStrategy();
            if (strategy == null) {
                createBufferStrategy(BUFFER);
                return;
            }

            this.field.render(this.game);

            for (int i = 0; i < getWidth() * getHeight(); i++) {
                this.pixels[i] = this.field.getPixels()[i];
            }

            Graphics g = strategy.getDrawGraphics();
            g.fillRect(0, 0, getWidth(), getHeight());
            g.drawImage(this.img, 0, 0, getWidth(), getHeight(), null);
            g.dispose();
            strategy.show();
        }
    }

    /**
     * Links this Window to the running game.
     * 
     * @param instGame
     *            the instantiated Game
     */
    public void setGame(final GameAPI instGame) {
        this.game = instGame;
    }

}
